package com.pi.shisan.service.schedule;

import com.pi.shisan.common.NumberUtil;
import com.pi.shisan.component.util.ComponentThread;
import com.pi.shisan.util.DefaultFont8x8;
import com.pi.shisan.util.spipoint.MultipleFlushSpi;

import java.util.ArrayList;
import java.util.List;

/**
 * 不是线程安全的
 */
public class LoadingComponent {

    private volatile LoadingThread thread;

    private static volatile LoadingComponent loadingComponent;

    private static volatile boolean hasShow = false;

    public static void showOnce(MultipleFlushSpi spi) {
        if (hasShow) {
            return;
        }
        hasShow = true;
        if (loadingComponent == null) {
            synchronized (LoadingComponent.class) {
                if (loadingComponent == null) {
                    loadingComponent = new LoadingComponent();
                    loadingComponent.start(spi);
                }
            }
        }
    }

    public static void close() {
        if (loadingComponent != null) {
            loadingComponent.stop();
            loadingComponent = null;
            System.gc();
        }
    }

    private void start(MultipleFlushSpi spi) {
        if (thread == null) {
            synchronized (this) {
                if (thread == null) {
                    thread = new LoadingThread(spi);
                    thread.start();
                }
            }
        }
    }

    private void stop() {
        if (thread != null) {
            thread.close();
            thread = null;
        }
    }

    public static boolean isOver() {
        return hasShow && loadingComponent == null;
    }

    public static class LoadingThread extends Thread {

        private volatile boolean closed = false;

        private volatile boolean finishedClose = false;

        private MultipleFlushSpi spi;

        public LoadingThread(MultipleFlushSpi spi) {
            this.spi = spi;
        }

        @Override
        public void run() {
            try {
                show();
            } finally {
                finishedClose = true;
            }
        }

        private void show() {
            long []points = DefaultFont8x8.GIF_CIRCLE_LOADING;
            List<int[]> xyPoints = new ArrayList<>(points.length);
            int w = spi.getW() * 8;
            int h = spi.getH() * 8;
            int startX = w/2 - 4;
            int startY = h/2 - 4;
            for (long p : points) {
                int[] xys = DefaultFont8x8.getPointsAsXy(p);
                for (int i = 0; i < xys.length; i++) {
                    int x = NumberUtil.toX(xys[i]);
                    int y = NumberUtil.toY(xys[i]);
                    xys[i] = NumberUtil.toXy((short)(x + startX), (short)(y + startY));
                }
                xyPoints.add(xys);
            }
            int[] finishedClear = null;
            int index = xyPoints.size() - 1;
            while (!closed) {
                int[] last = xyPoints.get(index++);
                if (index >= xyPoints.size()) {
                    index = 0;
                }
                int[] curr = xyPoints.get(index);
                ComponentThread.execute(()->{
                    for (int xy : last) {
                        spi.delete(xy);
                    }
                    for (int xy : curr) {
                        spi.put(xy);
                    }
                    spi.flushData();
                });
                finishedClear = curr;
                try {
                    Thread.sleep(50);
                } catch (InterruptedException e) {
                }
            }
            if (finishedClear != null) {
                for (int xy : finishedClear) {
                    spi.delete(xy);
                }
                spi.flushData();
            }
        }

        public void close() {
            closed = true;
            this.interrupt();
            while (!finishedClose) {
                Thread.yield();
            }
        }

    }

}
